home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…eptember: Technology Seed / September 98 ADC Seed CD.toast / FireWire 1.1 DR2 SDK / Source / FWiX / FWiXDriver / FWiXDriver.c next >
Encoding:
Text File  |  1998-01-15  |  65.3 KB  |  2,135 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWiXDriver.c
  3.  
  4.     Contains:    Driver software for FireWire File Exchange.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.  
  10.     Copyright:    © 1996-1997 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (jkl)    Jay Lloyd
  23.  
  24.     Change History (most recent first):
  25.  
  26.         <27>     5/28/97    jkl        Added a check for control packet index equal to 1 for a node
  27.                                     being restarted. Cleaned up some of the inUse and timing checks
  28.                                     added in last revision to investigate 5+ node problem.
  29.       <FW26>     5/27/97    jkl        Added a control packet indexing function to make sure control
  30.                                     packets are handled only once. Changed the flow control timer to
  31.                                     send flow control requests until a reply is received. This would
  32.                                     fix a case where a flow control request never got a reply.
  33.                                     Added more error checking and in use checking to investigate 5+
  34.                                     node problem.
  35.       <FW25>     5/15/97    jkl        Added a checksum routine around send data and data done. Added
  36.                                     an index to the flow control messages to only handle a reply
  37.                                     from the latest request. Put a check around sendpacket to make
  38.                                     sure it is not reentered.
  39.       <FW24>     2/27/97    jkl        Modified the WriteDataComplete routine to turn off flow control.
  40.                                     This will cause a flow control request and reply to be sent to
  41.                                     ensure the receive data buffer does not get overwritten with
  42.                                     more data before the receiver reads the existing data out of the
  43.                                     buffer. Reduced flow control retry time from 100 to 10 ms to
  44.                                     reduce transfer stalls.
  45.       <FW23>     2/21/97    ES        Added in use flags for all FWCommandObjects. Changed FWXClose to
  46.                                     wait for all of these flags to clear before doing any closing
  47.                                     activity. Removed wait on writePending. This fixes a hang on
  48.                                     closing bug.
  49.       <FW22>     2/21/97    EA        Added option to send diagnostic messages to FireBug.
  50.       <FW21>     2/21/97    jkl        Modified data transmissions to be sent to non-notify address
  51.                                     space.
  52.       <FW20>     2/20/97    ES        Changed FWClientAsynchRequestParams buffer field to
  53.                                     receiveBuffer.
  54.       <FW19>     2/19/97    jkl        Added a flow control send pending flag to make sure two messages
  55.                                     do not get sent at one time. Moved available buffer counts from
  56.                                     write completion routine to write routine.
  57.       <FW18>     2/14/97    jkl        Changed the flow control mechanism so the sender has to request
  58.                                     from the receiver how many packets he can send.
  59.       <FW17>     2/13/97    jkl        Added FlowControl packet counter to make sure flow control is
  60.                                     started properly.
  61.       <FW16>     2/13/97    jkl        Changed flow control to just keep up with number of data packets
  62.                                     available and sent. The flow control message is only sent when
  63.                                     all of the read packets have been received and are available,
  64.                                     thus the sender will stall after each number of sends. Changed
  65.                                     write notify routine to complete read data transaction when
  66.                                     requested data is equal to received data.
  67.       <FW15>     2/11/97    ES        Added closed boolean to FWXNodeData record. Added checks for
  68.                                     node being closed to prevent any writes going out or being
  69.                                     processed when we're closing a node connection. Changed write
  70.                                     queue deallocation to wait until no more writes are pending
  71.                                     before deallocating queue.
  72.       <FW14>     2/11/97    jkl        Added support for read control and data queues. Changed flow
  73.                                     control to a you can send me this much mechanism. Moved
  74.                                     FWXCommandComplete routine to the family.
  75.       <FW13>      2/2/97    jkl        Modified flow control time delay to check more often if it is ok
  76.                                     to write and write routine to handle writing buffers larger than
  77.                                     the allocated firewire buffer size.
  78.       <FW12>     1/27/97    ES        Changed FWXWrite to make sure there is still an item on the
  79.                                     write queue before processing the head of the queue (a race
  80.                                     condition was happening here). Changed FWXCloseNode to check if
  81.                                     the read and write queues were non-nil before deallocating.
  82.       <FW11>     1/16/97    ES        Changed FWXCreatePDriverUnitDirectory to set CSRROMEntryID's to
  83.                                     invalid before using them. Also, added code to deallocate entry
  84.                                     ID's.
  85.       <FW10>     1/16/97    jkl        Cleaned up read/write buffers on close.
  86.        <FW9>      1/8/97    ES        Changed to a FireWire protocol driver. Removed fixed FireWire
  87.                                     address allocation.
  88.        <FW8>    12/27/96    ES        Changed a bunch of "FWDriver"s to "FWClient"s.
  89.        <FW7>    12/16/96    ES        Changed to work with new read/write/lock request/complete
  90.                                     processing mechanism.
  91.        <FW6>     12/3/96    ES        Added kFWFixedAddress flag to FWAllocateAddressSpace.
  92.        <FW5>    11/13/96    jkl        Moved from DoDriverIO interface back to CallDriver. Added
  93.                                     multiple machine support. Added packet receive buffering.
  94.        <FW4>     10/31/96    jkl        Added flow control constants.
  95.        <FW3>     10/13/96    jkl        Added a basic flow control capability to turn off transmission
  96.                                        when the number of received buffers is low. All queue routines
  97.                                     are now the dsl queue routines. The ioMisc field in a parameter
  98.                                     block is now used to identify the packet type. For control
  99.                                     packets, the packet type is still also in the first long word
  100.                                     of the buffer. A sendpacket routine is now called by the write
  101.                                     handler and the write completion handler to send a packet. Fork
  102.                                     data is sent to a separate address space that is now set to write
  103.                                     notify.
  104.        <FW2>     10/3/96    jkl        Changed to use set driver interface calls rather than driver
  105.                                     interface table.
  106.        <FW1>     10/2/96    jkl        initial check-in, copied from avt driver
  107.                                        Added DoDriverIO interface.
  108.  
  109. */
  110.  
  111. #include <Types.h>
  112. #include <Errors.h>
  113. #include <Devices.h>
  114. #include <DriverServices.h>
  115. #include <FireWire.h>
  116.  
  117. #include "FWiX.h"
  118. #include "FWiXDriver.h"
  119.  
  120. #include <stdio.h>
  121. char  debugStr[256];
  122. static pascal void FWDebugStr(
  123.     ConstStr255Param            debuggerMsg)
  124. {
  125. #ifdef FW_DEBUG_BUILD
  126. #if FW_DEBUG_BUILD
  127.     DebugStr (debuggerMsg);
  128. #endif
  129. #endif
  130. }
  131.  
  132.  
  133. // define FireBug to enable sending diagnostic messages to FireBug on the fly.
  134. // WARNING:  Read the notes below first.  Be sure use "tcode on 1" in FireBug
  135. // so that you can see the messages.  [Also use "ack 0" if you don't want to
  136. // see many other packets]
  137.  
  138. //#define FireBug
  139. #ifdef FireBug
  140. static char fireBug[256];
  141. static FWReferenceID fireBugID;
  142. static FWCommandObjectID fireBugCommandObjectID;
  143. static UInt32 fireBugNeedCommandObject = 1;
  144.  
  145. static void FireBugMsg (char * msg)
  146. {
  147.     FWTopologyMap topology;
  148.     OSStatus status;
  149.     
  150.     if (fireBugNeedCommandObject) return;
  151.     
  152.     // It would probably be more safe to add a mechanism to make sure the
  153.     // most recent FireBugMsg completed before we recycle the command object.
  154.     // But I expect that the FWGetTopologyMap will probably take care of this.
  155.     
  156.     status = FWGetTopologyMap (fireBugID, &topology);
  157.     status = FWSetAsynchCommandGeneration (fireBugCommandObjectID, topology.generationNumber);
  158.     status = FWSetAsynchCommandBuffer (fireBugCommandObjectID, msg);
  159.     status = FWSetAsynchCommandLength (fireBugCommandObjectID, strlen (msg) + 1);
  160.     status = FWWrite (fireBugCommandObjectID);
  161. }
  162.  
  163. static void FireBugPrep (FWReferenceID tempID)
  164. {
  165.     OSStatus status;
  166.     
  167.     if (fireBugNeedCommandObject)
  168.     {
  169.         status = FWAllocateAsynchCommandObject (&fireBugCommandObjectID);
  170.         if (status == noErr)
  171.         {            
  172.             FWGetLocalFWReferenceIDFromFWReferenceID (tempID, &fireBugID);
  173.  
  174.             FWSetFWCommandParams(fireBugCommandObjectID, fireBugID, 0, nil, 0);
  175.             FWSetCommonAsynchCommandParams (fireBugCommandObjectID,
  176.                                             0x42420000, 0x00000000,
  177.                                             (Ptr) fireBug, sizeof (fireBug));
  178.             FWSetAsynchCommandMaxRetries (fireBugCommandObjectID, 0);
  179.             FWSetAsynchCommandMaxPayloadSize (fireBugCommandObjectID, 512);
  180.             FWSetAsynchCommandTransferFlags (fireBugCommandObjectID,
  181.                                              kFWAsynchAbsoluteAddress |
  182.                                              kFWAsynchOverrideMaxPayload);
  183.         }
  184.     
  185.         fireBugNeedCommandObject = 0;
  186.     }
  187. }
  188. #endif
  189.  
  190.  
  191. ////////////////////////////////////////////////////////////////////////////////
  192. //
  193. // Internal procedure prototypes.
  194. //
  195.  
  196. static void HandleFlowControlNotify (
  197.     FWXNodeDataPtr                pFWXNodeData,
  198.     Ptr                            pMessage);
  199.  
  200. static void HandleControlNotify (
  201.     FWXNodeDataPtr                pFWXNodeData,
  202.     Ptr                            pMessage,
  203.     UInt32                        msgLength);
  204.  
  205. static void HandleDataDone (
  206.     FWXNodeDataPtr                pFWXNodeData,
  207.     UInt32                        count,
  208.     UInt32                        checkSum);
  209.  
  210. static OSStatus    FWPDriverUnitAdded (
  211.     FWPDriverID                    fwPDriverID,
  212.     UInt32                        fwPDriverSpecificData,
  213.     FWUnitID                    fwUnitID);
  214.  
  215. static OSStatus    FWPDriverUnitRemoved (
  216.     FWPDriverID                    fwPDriverID,
  217.     UInt32                        fwPDriverSpecificData,
  218.     FWUnitID                    fwUnitID);
  219.  
  220. static void FlowControlComplete (
  221.     FWCommandObjectID            fwCommandObjectID,
  222.     OSStatus                    commandStatus,
  223.     UInt32                        completionProcData);
  224.  
  225. static void FlowControlReplyComplete (
  226.     FWCommandObjectID            fwCommandObjectID,
  227.     OSStatus                    commandStatus,
  228.     UInt32                        completionProcData);
  229.  
  230. static OSStatus FWXRead (
  231.     FWXAsynchParamsPtr            pFWXAsynchParams);
  232.  
  233. static OSStatus FWXWrite (
  234.     FWXAsynchParamsPtr            pFWXAsynchParams);
  235.  
  236. static void DataDoneComplete(
  237.     FWCommandObjectID            fwCommandObjectID,
  238.     OSStatus                    commandStatus,
  239.     UInt32                        completionProcData);
  240.  
  241. static void HandleWriteDataComplete(
  242.     FWCommandObjectID            fwCommandObjectID,
  243.     FWXNodeDataPtr                pFWXNodeData,
  244.     IOParamPtr                    pCompleteIOPb);
  245.  
  246. static void HandleWriteControlComplete(
  247.     FWCommandObjectID            fwCommandObjectID,
  248.     FWXNodeDataPtr                pFWXNodeData,
  249.     IOParamPtr                    pCompleteIOPb);
  250.  
  251. static void FWXWriteCompletion (
  252.     FWCommandObjectID            fwCommandObjectID,
  253.     OSStatus                    commandStatus,
  254.     UInt32                        completionProcData);
  255.  
  256. static OSStatus RetryFlowControl (
  257.     void                        *p1,
  258.     void                        *p2);
  259.  
  260. static OSStatus SendDataPacket(
  261.     FWXNodeDataPtr                pFWXNodeData,
  262.     IOParamPtr                    pb,
  263.     UInt32                        length);
  264.  
  265. static OSStatus SendControlPacket(
  266.     FWXNodeDataPtr                pFWXNodeData,
  267.     IOParamPtr                    pb,
  268.     UInt32                        length);
  269.  
  270. static OSStatus SendPacket (
  271.     FWXNodeDataPtr                pNodeData);
  272.     
  273. static OSStatus    FWXInitialize (
  274.     FWXInitializeParamsPtr        pFWXInitializeParams);
  275.  
  276. static OSStatus    FWXCreatePDriverUnitDirectory (
  277.     FWXDriverDataPtr            pFWXDriverData,
  278.     CSRROMEntryID                *pFWPDriverCSRROMUnitDirID);
  279.  
  280. static OSStatus    FWXTerminate (
  281.     FWXTerminateParamsPtr        pFWXTerminateParams);
  282.  
  283. static OSStatus FWXOpenNode (
  284.     FWXOpenNodeParamsPtr        pFWXInitializeParams);
  285.  
  286. static OSStatus FWXCloseNode (
  287.     FWXNodeDataPtr                pFWXNodeData);
  288.  
  289. static OSStatus SetupIOQueues (
  290.     FWXNodeDataPtr                pFWXNodeData);
  291.  
  292. static OSStatus FWXGetNodeDataFromNodeID (
  293.     FWXDriverDataPtr            pFWXDriverData,
  294.     UInt32                        generation,
  295.     UInt32                        nodeID,
  296.     FWXNodeDataPtr                *ppFWXNodeData);
  297.  
  298. ////////////////////////////////////////////////////////////////////////////////
  299. //
  300. // The driver descriptor.
  301. //
  302.  
  303. DriverDescription                 TheDriverDescription =
  304. {
  305.     kTheDescriptionSignature,
  306.     kInitialDriverDescriptor,
  307.     {
  308.         "\pFWiX",
  309.         1, 0, developStage, 1,
  310.     },
  311.     {
  312.         0                                        // driver runtime options
  313.         | (0 * kDriverIsLoadedUponDiscovery)
  314.         | (0 * kDriverIsOpenedUponLoad)
  315.         | (1 * kDriverIsUnderExpertControl)
  316.         | (1 * kDriverIsConcurrent)
  317.         | (1 * kDriverQueuesIOPB),
  318.         "\pFWiXDriver",
  319.     },
  320.  
  321.     1,
  322.     kServiceCategoryFWiX,
  323.     0,
  324.     1,0,0,0
  325. };
  326.     
  327. FWPDriverDescription            ThePDriverDescription =
  328. {
  329.     kTheFWPDriverDescriptionSignature,
  330.     kInitialFWPDriverDescriptor,
  331.  
  332.     kServiceCategoryFWDriver,
  333.     0,0,developStage,0,
  334.  
  335.     0,
  336.     "\pFWiX"
  337. };
  338.  
  339. ////////////////////////////////////////////////////////////////////////////////
  340. //
  341. //    FWClientWriteRequestInterface
  342. //
  343. //    Handle writes to the client. Check the type of received data by address
  344. //    space id. Set flow control information. If the data is control information
  345. //    send any file data information to the application then send the control
  346. //    information. If the data is file data add it to the receive buffer, if it
  347. //    overflows the receive buffer, send the buffer to the app and get a new one.
  348. //
  349.  
  350. OSStatus FWClientWriteCompleteInterface(
  351.     FWClientAsynchRequestParamsPtr
  352.                                 pFWClientAsynchRequestParams,
  353.     UInt32                        *pCommandAcceptance)
  354. {
  355.     FWXDriverDataPtr            pFWXDriverData;
  356.     FWXNodeDataPtr                pFWXNodeData;
  357.     OSStatus                    status = noErr;
  358.  
  359.     // recover our node data
  360.     //zzz check status
  361.     pFWXDriverData = (FWXDriverDataPtr) pFWClientAsynchRequestParams->pAddressSpecificData;
  362.     status = FWXGetNodeDataFromNodeID (pFWXDriverData,
  363.                                        pFWClientAsynchRequestParams->generation,
  364.                                        pFWClientAsynchRequestParams->sourceID,
  365.                                        &pFWXNodeData);
  366.  
  367.     if (status == noErr)
  368.     {
  369.         if (pFWClientAsynchRequestParams->fwAddressSpaceID == pFWXDriverData->fcAddressSpaceID)
  370.             
  371.             HandleFlowControlNotify (pFWXNodeData,
  372.                                      pFWClientAsynchRequestParams->receiveBuffer);
  373.                                      
  374.         else if (pFWClientAsynchRequestParams->fwAddressSpaceID == pFWXDriverData->controlAddressSpaceID)
  375.             
  376.             HandleControlNotify (pFWXNodeData,
  377.                                  pFWClientAsynchRequestParams->receiveBuffer,
  378.                                  pFWClientAsynchRequestParams->length);
  379.     }
  380.  
  381.     // Complete FireWire client command.
  382.     FWClientCommandIsComplete
  383.         (pFWClientAsynchRequestParams->fwClientInterfaceParams.fwClientCommandID,
  384.          status);
  385.  
  386.     // Return command acceptance.
  387.     //zzz is this the right way?  If we've completed the command, we can accept more.
  388.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  389.  
  390.     return status;
  391. }
  392.  
  393. ////////////////////////////////////////////////////////////////////////////////
  394. //
  395. // HandleFlowControlNotify
  396. //
  397. //    Handle notification of a flow control message received. If the message
  398. //    is a request, reply with the appropriate flow control value. If the
  399. //    message is a reply and there are now receive buffers available, try
  400. //    sending a packet. If there are no buffers available start a timer to
  401. //    wait and then send another flow control request.
  402. //
  403.  
  404. static void HandleFlowControlNotify (
  405.     FWXNodeDataPtr            pFWXNodeData,
  406.     Ptr                        pMessage)
  407. {
  408.     UInt32                    fcPacketCount;
  409.     UInt32                    messageType;
  410.     AbsoluteTime            fcRequestDelay;
  411.     OSStatus                status = noErr;
  412.     
  413.     messageType = ((UInt32 *) pMessage)[0];
  414.     switch (messageType)
  415.     {
  416.         case kFCDataRequest:
  417.             if (!pFWXNodeData->fcReplyCommandObjectInUse)
  418.             {
  419.                 pFWXNodeData->fcReplyBuffer[0] = kFCDataReply;
  420.                 pFWXNodeData->fcReplyBuffer[1] = pFWXNodeData->dataPbCount;
  421.                 pFWXNodeData->fcReplyBuffer[2] = ((UInt32 *) pMessage)[2];
  422.                 pFWXNodeData->fcReplyCommandObjectInUse = true;
  423.                 FWSetFWCommandCompletionProcData (pFWXNodeData->fcReplyCommandObjectID, (UInt32) pFWXNodeData);
  424.                 FWSetCommonAsynchCommandParams (pFWXNodeData->fcReplyCommandObjectID,
  425.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  426.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  427.                                                 (Ptr) pFWXNodeData->fcReplyBuffer,
  428.                                                 kFlowControlSize);
  429.                 status = FWWrite(pFWXNodeData->fcReplyCommandObjectID);
  430.                 if (status != noErr)
  431.                     pFWXNodeData->fcReplyCommandObjectInUse = false;                    
  432.             }
  433.             break;
  434.         
  435.         case kFCControlRequest:
  436.             if (!pFWXNodeData->fcReplyCommandObjectInUse)
  437.             {
  438.                 pFWXNodeData->fcReplyBuffer[0] = kFCControlReply;
  439.                 pFWXNodeData->fcReplyBuffer[1] = pFWXNodeData->controlPbCount;
  440.                 pFWXNodeData->fcReplyBuffer[2] = ((UInt32 *) pMessage)[2];
  441.                 pFWXNodeData->fcReplyCommandObjectInUse = true;
  442.                 FWSetFWCommandCompletionProcData (pFWXNodeData->fcReplyCommandObjectID, (UInt32) pFWXNodeData);
  443.                 FWSetCommonAsynchCommandParams (pFWXNodeData->fcReplyCommandObjectID,
  444.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  445.                                                 pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  446.                                                 (Ptr) pFWXNodeData->fcReplyBuffer,
  447.                                                 kFlowControlSize);
  448.                 status = FWWrite(pFWXNodeData->fcReplyCommandObjectID);
  449.                 if (status != noErr)
  450.                     pFWXNodeData->fcReplyCommandObjectInUse = false;                    
  451.             }
  452.             break;
  453.         
  454.         case kFCDataReply:
  455.             fcPacketCount = ((UInt32 *) pMessage)[2];
  456.             CancelTimer(pFWXNodeData->fcTimerID, &fcRequestDelay);
  457.             if (fcPacketCount == pFWXNodeData->fcIndex)
  458.             {
  459.                 pFWXNodeData->fcIndex++;
  460.                 pFWXNodeData->dataPbAvail = ((SInt32 *) pMessage)[1];
  461.                 if (pFWXNodeData->dataPbAvail > 0)
  462.                 {
  463.                     if (pFWXNodeData->fcStopSend)
  464.                     {
  465.                         // there were no buffers before, now there are some, restart sending
  466.                         pFWXNodeData->fcStopSend = false;
  467.                         status = SendPacket(pFWXNodeData);
  468.                     }
  469.                 }
  470.                 else
  471.                 {
  472.                     // still no buffers available, reset timer
  473.                     fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 20 milliseconds
  474.                 status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  475.                                             RetryFlowControl,
  476.                                             (void *) pFWXNodeData,
  477.                                             &pFWXNodeData->fcTimerID);
  478.             }
  479.             }
  480.             else
  481.             {
  482.                 // received flow control message out of order, retry
  483.                 fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 20 milliseconds
  484.                 status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  485.                                             RetryFlowControl,
  486.                                             (void *) pFWXNodeData,
  487.                                             &pFWXNodeData->fcTimerID);
  488.             }
  489.             break;
  490.         
  491.         case kFCControlReply:
  492.             fcPacketCount = ((UInt32 *) pMessage)[2];
  493.             CancelTimer(pFWXNodeData->fcTimerID, &fcRequestDelay);
  494.             if (fcPacketCount == pFWXNodeData->fcIndex)
  495.             {
  496.                 pFWXNodeData->fcIndex++;
  497.                 pFWXNodeData->controlPbAvail = ((SInt32 *) pMessage)[1];
  498.                 if (pFWXNodeData->controlPbAvail > 0)
  499.                 {
  500.                     if (pFWXNodeData->fcStopSend)
  501.                     {
  502.                         pFWXNodeData->fcStopSend = false;
  503.                         status = SendPacket(pFWXNodeData);
  504.                     }
  505.                 }
  506.                 else
  507.                 {
  508.                     // still no buffers available, reset timer
  509.                     fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 20 milliseconds
  510.                     status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  511.                                                 RetryFlowControl,
  512.                                                 (void *) pFWXNodeData,
  513.                                                 &pFWXNodeData->fcTimerID);
  514.                 }
  515.             }
  516.             else
  517.             {
  518.                 fcRequestDelay = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute(20));        // 10 milliseconds
  519.                 status = SetInterruptTimer (&fcRequestDelay,                                    // JKL *** what's a good delay
  520.                                             RetryFlowControl,
  521.                                             (void *) pFWXNodeData,
  522.                                             &pFWXNodeData->fcTimerID);
  523.             }
  524.             break;
  525.         
  526.         case kAddressInfoRequest:
  527.             if (!pFWXNodeData->fcReplyCommandObjectInUse)
  528.             {
  529.             pFWXNodeData->remoteDataAddress.addressHi = ((UInt32 *) pMessage)[1];
  530.             pFWXNodeData->remoteDataAddress.addressLo = ((UInt32 *) pMessage)[2];
  531.             pFWXNodeData->fcReplyBuffer[0] = kAddressInfoReply;
  532.             pFWXNodeData->fcReplyBuffer[1] = pFWXNodeData->localDataAddress.addressHi;
  533.             pFWXNodeData->fcReplyBuffer[2] = pFWXNodeData->localDataAddress.addressLo;
  534.             pFWXNodeData->fcReplyCommandObjectInUse = true;
  535.             FWSetFWCommandCompletionProcData (pFWXNodeData->fcReplyCommandObjectID, (UInt32) pFWXNodeData);
  536.             FWSetCommonAsynchCommandParams (pFWXNodeData->fcReplyCommandObjectID,
  537.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  538.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  539.                                             (Ptr) pFWXNodeData->fcReplyBuffer,
  540.                                             kFlowControlSize);
  541.             status = FWWrite(pFWXNodeData->fcReplyCommandObjectID);
  542.                 if (status != noErr)
  543.                     pFWXNodeData->fcReplyCommandObjectInUse = false;                    
  544.             }
  545.             else
  546.             {
  547.                 FWDebugStr("\paddress info request, object in use");
  548.             }
  549.             break;
  550.             
  551.         case kAddressInfoReply:
  552.             pFWXNodeData->remoteDataAddress.addressHi = ((UInt32 *) pMessage)[1];
  553.             pFWXNodeData->remoteDataAddress.addressLo = ((UInt32 *) pMessage)[2];
  554.             break;
  555.             
  556.         default:
  557.             sprintf(debugStr,"fcNotify, message type unknown: %d", messageType);
  558.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  559.             break;
  560.     }
  561.         
  562.     if (status != noErr)
  563.     {
  564.         sprintf(debugStr,"fcNotify, error in FWWrite: %d", status);
  565.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  566.     }
  567. }
  568.  
  569. ////////////////////////////////////////////////////////////////////////////////
  570. //
  571. // HandleControlNotify
  572. //
  573. //    Handle notification of a control message received. If the message is data
  574. //    done, complete the data request, else complete the control request.
  575. //
  576.  
  577. static void HandleControlNotify (
  578.     FWXNodeDataPtr                pFWXNodeData,
  579.     Ptr                            pMessage,
  580.     UInt32                        msgLength)
  581. {
  582.     IOParamPtr                    pb;
  583.     UInt32                        packetType;
  584.     UInt32                        packetIndex;
  585.     OSStatus                    status = noErr;
  586.  
  587.     
  588.     packetIndex = ((UInt32 *) pMessage)[0];
  589.     if ((packetIndex > pFWXNodeData->lastIndex) || (packetIndex == 1))    // will be one if fwix is closed
  590.     {                                                                    // and opened on other machine
  591.         pFWXNodeData->lastIndex = packetIndex;
  592.         packetType = ((UInt32 *) pMessage)[1];
  593.     
  594.         if (packetType == kDataDone)
  595.         {
  596.                 HandleDataDone(pFWXNodeData, ((UInt32 *) pMessage)[2], ((UInt32 *) pMessage)[3]);
  597.         }
  598.         else
  599.         {        
  600.             // handle control packet
  601.             pb = (IOParamPtr) pFWXNodeData->pReadControlQHdr->qHead;
  602.             if (pb != nil)
  603.             {
  604.                 pFWXNodeData->controlPbCount--;
  605.                 if (pFWXNodeData->controlPbCount < 0)
  606.                     FWDebugStr("\pcontrol buffer count < 0, ControlNotify");
  607.                 PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pb);
  608.                 BlockMoveData(pMessage, pb->ioBuffer, msgLength);
  609.                 pb->ioActCount = msgLength;
  610.                 pb->ioMisc = (Ptr) packetType;
  611.                 FWXCommandIsComplete(pb, status);
  612.             }
  613.             else
  614.             {
  615.                 FWDebugStr("\pNo receive control buffer, WriteNotify");
  616.             }
  617.         }
  618.     }
  619.     else
  620.     {
  621.         sprintf(debugStr,"echo packet, last: %ld, received: %ld", pFWXNodeData->lastIndex, packetIndex);
  622.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  623.     }
  624. }
  625.     
  626. ////////////////////////////////////////////////////////////////////////////////
  627. //
  628. // HandleDataDone
  629. //
  630. //    Handle notification of a data done message. If the data completes the
  631. //    request, send the packet to the app. If the data overflows the request, send
  632. //    the current packet to the app and start a new one. Otherwise just copy the data
  633. //    into the current packet.
  634. //
  635.  
  636. static void HandleDataDone (
  637.     FWXNodeDataPtr                pFWXNodeData,
  638.     UInt32                        count,
  639.     UInt32                        checkSum)
  640. {
  641.     IOParamPtr                    pb;
  642.     UInt32                        byteCount;
  643.     UInt32                        dataSum;
  644.     OSStatus                    status = noErr;
  645.  
  646.     pb = (IOParamPtr) pFWXNodeData->pReadDataQHdr->qHead;    
  647.     if (pb != nil)
  648.     {
  649.         dataSum = 0;
  650.         for (byteCount = 0; byteCount < count; ++byteCount)
  651.             dataSum += (pFWXNodeData->dataBuffer)[byteCount];
  652.         
  653.         if (dataSum != checkSum)
  654.         {
  655.             status = badCksmErr;
  656.             sprintf(debugStr,"Checksum error, expected: %ld, received: %ld", checkSum, dataSum);
  657.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  658.         }
  659.         
  660.         BlockMoveData (pFWXNodeData->dataBuffer,
  661.                        pb->ioBuffer + pb->ioActCount,
  662.                        count);
  663.         pb->ioActCount += count;
  664.  
  665.         pFWXNodeData->dataPbCount--;
  666.         if (pFWXNodeData->dataPbCount < 0)
  667.             FWDebugStr("\pdataPbCount < 0, data done");
  668.  
  669.             PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pb);
  670.             pb->ioMisc = (Ptr) kForkData;
  671.             FWXCommandIsComplete(pb, status);
  672.         }
  673.     else
  674.         FWDebugStr("\pNo receive buffer for data, data done");
  675. }
  676.  
  677.  
  678. ////////////////////////////////////////////////////////////////////////////////
  679. //
  680. // FWPDriverUnitAdded
  681. //
  682. //   FireWire protocol driver interface for handling added units.
  683. //
  684.  
  685. static OSStatus    FWPDriverUnitAdded(
  686.     FWPDriverID                    fwPDriverID,
  687.     UInt32                        fwPDriverSpecificData,
  688.     FWUnitID                    fwUnitID)
  689. {
  690.     FWXDriverDataPtr            pFWXDriverData;
  691.     OSStatus                    status = noErr;
  692.  
  693.     // Get our driver data.
  694.     pFWXDriverData = (FWXDriverDataPtr) fwPDriverSpecificData;
  695.  
  696.     status = RegisterFWXNode (pFWXDriverData->fwxDriverID, (UInt32) fwUnitID);
  697.  
  698.     return (status);
  699. }
  700.  
  701. ////////////////////////////////////////////////////////////////////////////////
  702. //
  703. // FWPDriverUnitRemoved
  704. //
  705. //   FireWire protocol driver interface for handling removed units.
  706. //
  707.  
  708. static OSStatus    FWPDriverUnitRemoved(
  709.     FWPDriverID                    fwPDriverID,
  710.     UInt32                        fwPDriverSpecificData,
  711.     FWUnitID                    fwUnitID)
  712. {
  713.     FWXDriverDataPtr            pFWXDriverData;
  714.     OSStatus                    status = noErr;
  715.  
  716.     // Get our driver data.
  717.     pFWXDriverData = (FWXDriverDataPtr) fwPDriverSpecificData;
  718.  
  719.     status = UnregisterFWXNode (pFWXDriverData->fwxDriverID, (UInt32) fwUnitID);
  720.  
  721.     return (status);
  722. }
  723.  
  724.  
  725. ////////////////////////////////////////////////////////////////////////////////
  726. //
  727. //    FlowControlCompletion
  728. //
  729. //    Completion routine for flow control message write
  730. //
  731.  
  732. static void FlowControlComplete(
  733.     FWCommandObjectID            fwCommandObjectID,
  734.     OSStatus                    commandStatus,
  735.     UInt32                        completionProcData)
  736. {
  737.     FWXNodeDataPtr            pFWXNodeData;
  738.  
  739.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  740.     pFWXNodeData->fcSendCommandObjectInUse = false;
  741.     if (commandStatus != noErr)
  742.     {
  743.         if ((commandStatus == timeoutErr) ||
  744.             (commandStatus == retryExceededErr) ||
  745.             (commandStatus == busReconfiguredErr))
  746.         {
  747.             pFWXNodeData->fcSendCommandObjectInUse = true;
  748.             commandStatus = FWWrite(fwCommandObjectID);
  749.             if (commandStatus != noErr)
  750.                 pFWXNodeData->fcSendCommandObjectInUse = false;
  751.         }
  752.         else
  753.         {
  754.         sprintf(debugStr,"Error in send flow control: %ld", commandStatus);
  755.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  756.     }
  757.     }
  758. }
  759.  
  760.  
  761. ////////////////////////////////////////////////////////////////////////////////
  762. //
  763. //    FlowControlReplyComplete
  764. //
  765. //    Completion routine for flow control reply write
  766. //
  767.  
  768. static void FlowControlReplyComplete(
  769.     FWCommandObjectID            fwCommandObjectID,
  770.     OSStatus                    commandStatus,
  771.     UInt32                        completionProcData)
  772. {
  773.     FWXNodeDataPtr            pFWXNodeData;
  774.  
  775.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  776.     pFWXNodeData->fcReplyCommandObjectInUse = false;
  777.     if (commandStatus != noErr)
  778.     {
  779.         if ((commandStatus == timeoutErr) ||
  780.             (commandStatus == retryExceededErr) ||
  781.             (commandStatus == busReconfiguredErr))
  782.         {
  783.             commandStatus = FWWrite(fwCommandObjectID);
  784.             if (commandStatus != noErr)
  785.                 pFWXNodeData->fcReplyCommandObjectInUse = false;
  786.         }
  787.         else
  788.         {
  789.         sprintf(debugStr,"Error in send flow control: %ld", commandStatus);
  790.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  791.     }
  792.     }
  793. }
  794.  
  795.  
  796. ////////////////////////////////////////////////////////////////////////////////
  797. //
  798. //    FWXRead
  799. //
  800. //    FWiX read routine. This is not a FireWire read routine. This is an
  801. //    interface for the FwiX application to pass read buffers to the
  802. //    driver to handle received data.
  803. //
  804. //    Queue the application parameter    blocks. The FWClientWriteCompleteInterface
  805. //    routine handles the rest. A counter keeps the number of read control parameter
  806. //    blocks which will tell the sender how many control commands it can send.
  807. //    Also keep up with the size of the data buffer to tell the sender how much
  808. //    data can be sent.
  809. //
  810.  
  811. static OSStatus FWXRead(
  812.     FWXAsynchParamsPtr        pFWXAsynchParams)
  813. {
  814.     FWXNodeDataPtr            pFWXNodeData;
  815.     IOParamPtr                pIOParam;
  816.     OSStatus                status = noErr;
  817.  
  818.     pFWXNodeData = (FWXNodeDataPtr) pFWXAsynchParams->fwxInterfaceParams.pNodeSpecificData;
  819.     pIOParam = pFWXAsynchParams->pIOPB;
  820.     
  821.     pIOParam->ioActCount = 0;
  822.     if (pIOParam->ioMisc == (Ptr) kForkData)
  823.     {
  824.         status = PBEnqueueLast((QElemPtr) pIOParam, pFWXNodeData->pReadDataQHdr);
  825.         pFWXNodeData->dataPbCount++;
  826.         if (pFWXNodeData->dataPbCount > 6)        // value from fwixmain.h
  827.             FWDebugStr("\pdata buffer count too high, FWXRead");
  828.     }
  829.     else
  830.     {
  831.         status = PBEnqueueLast((QElemPtr) pIOParam, pFWXNodeData->pReadControlQHdr);
  832.         pFWXNodeData->controlPbCount++;
  833.         if (pFWXNodeData->dataPbCount > 20)        // value from fwixmain.h
  834.             FWDebugStr("\pcontrol buffer count too high, FWXRead");
  835.     }
  836.         
  837.     return status;
  838. }
  839.  
  840.  
  841. ////////////////////////////////////////////////////////////////////////////////
  842. //
  843. //    FWXWrite
  844. //
  845. //    Queue the write request. If there are no writes in progress, go ahead and
  846. //    issue a write. Otherwise the queued write request will be picked up by
  847. //    the write completion routine.
  848. //
  849.  
  850. static OSStatus FWXWrite(
  851.     FWXAsynchParamsPtr        pFWXAsynchParams)
  852. {
  853.     FWXNodeDataPtr            pFWXNodeData;
  854.     IOParamPtr                pIOParam;
  855.     OSStatus                status = noErr;
  856.  
  857.     // recover driver data
  858.     pFWXNodeData = (FWXNodeDataPtr) pFWXAsynchParams->fwxInterfaceParams.pNodeSpecificData;
  859.     pIOParam = pFWXAsynchParams->pIOPB;
  860.  
  861.     // queue the parameter block
  862.     pIOParam->ioActCount = 0;
  863.     PBEnqueueLast((QElemPtr) pIOParam, pFWXNodeData->pWriteQHdr);
  864.     
  865.     if (!pFWXNodeData->writePending)
  866.     {    
  867.         pIOParam = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  868.         if (pIOParam != nil)
  869.         {
  870.             pFWXNodeData->writePending = true;    
  871.             pFWXNodeData->pCurIOParam = pIOParam;
  872.             status = SendPacket(pFWXNodeData);
  873.         }
  874.     }
  875.     return status;
  876. }
  877.  
  878.  
  879. ////////////////////////////////////////////////////////////////////////////////
  880. //
  881. //    DataDoneComplete
  882. //
  883. //    Data done complete routine. Set completion routine back to write complete
  884. //    for asynchCommandObject. Try sending another packet.
  885. //
  886.  
  887. static void DataDoneComplete(
  888.     FWCommandObjectID            fwCommandObjectID,
  889.     OSStatus                    commandStatus,
  890.     UInt32                        completionProcData)
  891. {
  892.     FWXNodeDataPtr                pFWXNodeData;
  893.     IOParamPtr                    pb;
  894.  
  895.     // recover node data
  896.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  897.  
  898.     // make sure node connection is still open
  899.     if (pFWXNodeData->closed)
  900.         commandStatus = notOpenErr;
  901.  
  902.     if (commandStatus == noErr)
  903.     {
  904.         FWSetFWCommandCompletionProc (fwCommandObjectID, FWXWriteCompletion);
  905.         pFWXNodeData->writeAsynchCommandObjectInUse = false;
  906.  
  907.         // check the queue for more parameter blocks to send
  908.         pb = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  909.         pFWXNodeData->pCurIOParam = pb;
  910.         if (pb != nil)
  911.             SendPacket(pFWXNodeData);
  912.         else
  913.             pFWXNodeData->writePending = false;
  914.     }
  915.     else if ((commandStatus == timeoutErr) ||
  916.             (commandStatus == retryExceededErr) ||
  917.             (commandStatus == busReconfiguredErr))
  918.     {
  919.         // try sending again
  920.         commandStatus = FWWrite(fwCommandObjectID);
  921.         if (commandStatus != noErr)
  922.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  923.     }
  924.     else
  925.     {
  926.         pFWXNodeData->writeAsynchCommandObjectInUse = false;
  927.         sprintf(debugStr, "Error in data done complete: %ld", commandStatus);
  928.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  929.     }
  930. }
  931.  
  932. ////////////////////////////////////////////////////////////////////////////////
  933. //
  934. //    HandleWriteDataComplete
  935. //
  936. //    Write data completion routine. If all of the requested data in the
  937. //    current parameter block has been sent, complete the command then
  938. //    dequeue another request and start sending it. If there are no requests
  939. //    waiting, set write complete to true and the next write request will restart
  940. //    the write/write complete loop.
  941. //
  942.  
  943. static void HandleWriteDataComplete(
  944.     FWCommandObjectID            fwCommandObjectID,
  945.     FWXNodeDataPtr                pFWXNodeData,
  946.     IOParamPtr                    pCompleteIOPb)
  947. {
  948.     IOParamPtr                    doneIOParam;
  949.     Ptr                            dataSent;
  950.     UInt32                        dataSum;
  951.     UInt32                        actCount;
  952.     UInt32                        byteCount;
  953.     OSStatus                    status;
  954.  
  955.     FWGetAsynchCommandBytesTransferred(fwCommandObjectID, &actCount);
  956.     pCompleteIOPb->ioActCount += actCount;
  957.     pFWXNodeData->dataPbAvail = 0;            // turn off flow control to allow for time
  958.                                             // for receiver to read data out of buffer
  959.     
  960.     pFWXNodeData->writeAsynchCommandObjectInUse    = false;
  961.     
  962.     FWGetAsynchCommandBuffer(fwCommandObjectID, &dataSent);
  963.     dataSum = 0;
  964.     for (byteCount = 0; byteCount < actCount; ++byteCount)
  965.         dataSum += dataSent[byteCount];
  966.     
  967.     pFWXNodeData->controlIndex++;
  968.     pFWXNodeData->dataDoneBuffer[0] = pFWXNodeData->controlIndex;
  969.  
  970.     // set packet type, data sent length, checksum
  971.     pFWXNodeData->dataDoneBuffer[1] = kDataDone;
  972.     pFWXNodeData->dataDoneBuffer[2] = actCount;
  973.     pFWXNodeData->dataDoneBuffer[3] = dataSum;
  974.  
  975.     if (!pFWXNodeData->writeAsynchCommandObjectInUse)
  976.     {
  977.     pFWXNodeData->writeAsynchCommandObjectInUse = true;
  978.     FWSetFWCommandCompletionProcData (fwCommandObjectID, (UInt32) pFWXNodeData);
  979.     FWSetCommonAsynchCommandParams (fwCommandObjectID,
  980.                                     pFWXNodeData->fwxUnitInfo.controlAddress.addressHi,
  981.                                     pFWXNodeData->fwxUnitInfo.controlAddress.addressLo,
  982.                                     (Ptr) pFWXNodeData->dataDoneBuffer,
  983.                                     kDataDoneBufSize);
  984.     FWSetFWCommandCompletionProc (fwCommandObjectID, DataDoneComplete);
  985.     
  986.         // send the data done notification after dequeuing the packet
  987.         status = FWWrite(pFWXNodeData->writeAsynchCommandObjectID);
  988.         if (status != noErr)
  989.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  990.         
  991.     // if all of the requested data was not sent, send some more
  992.     if (pCompleteIOPb->ioActCount < pCompleteIOPb->ioReqCount)
  993.     {
  994.         FWDebugStr("\pwrite data complete, should not be here");
  995.         SendPacket(pFWXNodeData);
  996.     }
  997.     else
  998.     {
  999.         // completed sending this parameter block, dequeue it and complete
  1000.         PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &doneIOParam);
  1001.         if (doneIOParam->ioCmdAddr != pCompleteIOPb->ioCmdAddr)
  1002.             FWDebugStr("\pWrite completion, queued pb not the same as completed pb");
  1003.         pFWXNodeData->pCurIOParam = nil;
  1004.         FWXCommandIsComplete(doneIOParam, noErr);
  1005.     }
  1006.     
  1007.     }
  1008.     else
  1009.         FWDebugStr("\pWriteDataComplete, writeAsynchCommandObjectInUse");
  1010. }
  1011.  
  1012. ////////////////////////////////////////////////////////////////////////////////
  1013. //
  1014. //    HandleWriteControlComplete
  1015. //
  1016. //    Write control completion routine. Complete the command then
  1017. //    dequeue another request and start sending it. If there are no requests
  1018. //    waiting, set write complete to true and the next write request will restart
  1019. //    the write/write complete loop.
  1020. //
  1021.  
  1022. static void HandleWriteControlComplete(
  1023.     FWCommandObjectID            fwCommandObjectID,
  1024.     FWXNodeDataPtr                pFWXNodeData,
  1025.     IOParamPtr                    pCompleteIOPb)
  1026. {
  1027.     IOParamPtr                    doneIOParam;
  1028.     UInt32                        actCount;            // count of bytes transferred
  1029.     OSErr                        err;
  1030.  
  1031.     FWGetAsynchCommandBytesTransferred(fwCommandObjectID, &actCount);
  1032.     pCompleteIOPb->ioActCount += actCount;
  1033.     
  1034.     // completed sending this parameter block, dequeue it and complete
  1035.     err = PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &doneIOParam);
  1036.     if (doneIOParam->ioCmdAddr != pCompleteIOPb->ioCmdAddr)
  1037.         FWDebugStr("\pWriteControlComplete, queued pb not the same as completed pb");
  1038.  
  1039.     FWXCommandIsComplete(doneIOParam, noErr);
  1040.     pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1041.     
  1042.     // check the queue for more parameter blocks to send
  1043.     pCompleteIOPb = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  1044.     pFWXNodeData->pCurIOParam = pCompleteIOPb;
  1045.     if (pCompleteIOPb != nil)
  1046.         SendPacket(pFWXNodeData);
  1047.     else
  1048.         pFWXNodeData->writePending = false;
  1049. }
  1050.  
  1051. ////////////////////////////////////////////////////////////////////////////////
  1052. //
  1053. //    FWXWriteCompletion
  1054. //
  1055. //    FWiX write completion routine. If all of the requested data in the
  1056. //    current parameter block has been sent, complete the command then
  1057. //    dequeue another request and start sending it. If there are no requests
  1058. //    waiting, set write complete to true and the next write request will restart
  1059. //    the write/write complete loop.
  1060. //
  1061.  
  1062. static void FWXWriteCompletion(
  1063.     FWCommandObjectID            fwCommandObjectID,
  1064.     OSStatus                    commandStatus,
  1065.     UInt32                        completionProcData)
  1066. {
  1067.     FWXNodeDataPtr                pFWXNodeData;
  1068.     IOParamPtr                    pIOParam;            // param block being processed
  1069.     IOParamPtr                    doneIOParam;        // param block being processed
  1070.  
  1071.     // recover original parameter block 
  1072.     pFWXNodeData = (FWXNodeDataPtr) completionProcData;
  1073.     pIOParam = pFWXNodeData->pCurIOParam;
  1074.  
  1075.     // make sure node connection is still open
  1076.     if (pFWXNodeData->closed)
  1077.         commandStatus = notOpenErr;
  1078.  
  1079.     // check transfer stats and increment actual bytes transferred
  1080.     if (commandStatus == noErr)
  1081.     {
  1082.         if (pIOParam->ioMisc == (Ptr) kForkData)
  1083.             HandleWriteDataComplete(fwCommandObjectID, pFWXNodeData, pIOParam);
  1084.         else
  1085.             HandleWriteControlComplete(fwCommandObjectID, pFWXNodeData, pIOParam);
  1086.     }
  1087.     else if ((commandStatus == timeoutErr) ||
  1088.             (commandStatus == retryExceededErr) ||
  1089.             (commandStatus == busReconfiguredErr))
  1090.     {
  1091.         // got a timeout error, try sending again
  1092.         //sprintf(debugStr, "Timeout error in WriteCompletion, pb: %lx", pIOParam);
  1093.         //FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1094.         SendPacket(pFWXNodeData);
  1095.     }
  1096.     else
  1097.     {
  1098.         // completion routine got an error
  1099.         sprintf(debugStr,"Error in write complete: %ld", commandStatus);
  1100.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1101.  
  1102.         pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1103.         PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &doneIOParam);
  1104.         pFWXNodeData->writePending = false;
  1105.         FWXCommandIsComplete(doneIOParam, commandStatus);
  1106.     }
  1107. }
  1108.  
  1109. ////////////////////////////////////////////////////////////////////////////////
  1110. //
  1111. //    RetryFlowControl
  1112. //
  1113. //    Timer-based routine to request if transmit continue. Check to see if
  1114. //    data transmit or control transmit is held and send appropriate request.
  1115. //
  1116. // JKL *** can another flow control write be pending? What if there is no
  1117. //    response?
  1118. //
  1119.  
  1120. static OSStatus RetryFlowControl(
  1121.     void                *p1,        // node data
  1122.     void                *p2)
  1123. {
  1124.     FWXNodeDataPtr        pFWXNodeData;
  1125.     IOParamPtr            pb;
  1126.     OSStatus            status = noErr;
  1127.     
  1128.     pFWXNodeData = (FWXNodeDataPtr) p1;
  1129.     pb = pFWXNodeData->pCurIOParam;
  1130.  
  1131.     // make sure node connection is still open
  1132.     if (pFWXNodeData->closed)
  1133.         status = notOpenErr;
  1134.  
  1135.     if ((status == noErr) && (!pFWXNodeData->fcSendCommandObjectInUse))
  1136.     {
  1137.         if (pb->ioMisc == (Ptr) kForkData)
  1138.             pFWXNodeData->fcSendBuffer[0] = kFCDataRequest;
  1139.         else
  1140.             pFWXNodeData->fcSendBuffer[0] = kFCControlRequest;
  1141.             
  1142.         pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->fcIndex;
  1143.         pFWXNodeData->fcSendCommandObjectInUse = true;
  1144.         FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1145.         FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1146.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1147.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1148.                                         (Ptr) pFWXNodeData->fcSendBuffer,
  1149.                                         kFlowControlSize);
  1150.         status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1151.         if (status != noErr)
  1152.         {
  1153.             pFWXNodeData->fcSendCommandObjectInUse = false;
  1154.         }
  1155.     }
  1156.     else
  1157.     {
  1158.         sprintf(debugStr,"Error in retry flow control: %ld", status);
  1159.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1160.     }
  1161.     return status;
  1162. }
  1163.  
  1164. ////////////////////////////////////////////////////////////////////////////////
  1165. //
  1166. //    SendDataPacket
  1167. //
  1168. //    Send a data packet. If the receive available packet counter is 0
  1169. //    then send a flow control request to the receiver to get the number
  1170. //    of receive buffers available.
  1171. //
  1172. static OSStatus SendDataPacket(
  1173.     FWXNodeDataPtr            pFWXNodeData,
  1174.     IOParamPtr                pb,
  1175.     UInt32                    length)
  1176. {
  1177.     OSStatus                status = noErr;
  1178.  
  1179.     if (pFWXNodeData->dataPbAvail > 0)
  1180.     {
  1181.         pFWXNodeData->dataPbAvail--;
  1182.         pFWXNodeData->writeAsynchCommandObjectInUse = true;
  1183.         FWSetFWCommandCompletionProcData (pFWXNodeData->writeAsynchCommandObjectID, (UInt32) pFWXNodeData);
  1184.         FWSetCommonAsynchCommandParams  (pFWXNodeData->writeAsynchCommandObjectID,
  1185.                                         pFWXNodeData->remoteDataAddress.addressHi,
  1186.                                         pFWXNodeData->remoteDataAddress.addressLo,
  1187.                                         pb->ioBuffer + pb->ioActCount,        // increment buffer address
  1188.                                         length);
  1189.         status = FWWrite(pFWXNodeData->writeAsynchCommandObjectID);
  1190.         if (status != noErr)
  1191.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1192.     }
  1193.     else
  1194.     {
  1195.         pFWXNodeData->fcStopSend = true;
  1196.         
  1197.         // JKL *** can another flow control write be pending? What if there is no
  1198.         //    response?
  1199.         if (!pFWXNodeData->fcSendCommandObjectInUse)
  1200.         {
  1201.             pFWXNodeData->fcSendBuffer[0] = kFCDataRequest;
  1202.             pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->fcIndex;
  1203.             pFWXNodeData->fcSendCommandObjectInUse = true;
  1204.             FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1205.             FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1206.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1207.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1208.                                             (Ptr) pFWXNodeData->fcSendBuffer,
  1209.                                             kFlowControlSize);
  1210.             status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1211.             if (status != noErr)
  1212.                 pFWXNodeData->fcSendCommandObjectInUse = false;
  1213.         }
  1214.     }
  1215.     return status;
  1216. }
  1217.  
  1218. ////////////////////////////////////////////////////////////////////////////////
  1219. //
  1220. //    SendControlPacket
  1221. //
  1222. //    Send a control packet. Make sure a control packet is allowed. If none
  1223. //    are allowed packet will be sent once allowed notification is received.
  1224. //
  1225.  
  1226. static OSStatus SendControlPacket(
  1227.     FWXNodeDataPtr            pFWXNodeData,
  1228.     IOParamPtr                pb,
  1229.     UInt32                    length)
  1230. {
  1231.     OSStatus                status = noErr;
  1232.  
  1233.     if (pFWXNodeData->controlPbAvail > 0)
  1234.     {
  1235.         pFWXNodeData->controlPbAvail--;
  1236.         pFWXNodeData->controlIndex++;
  1237.         *((UInt32 *) pb->ioBuffer) = pFWXNodeData->controlIndex;
  1238.         length += 4;
  1239.  
  1240.         pFWXNodeData->writeAsynchCommandObjectInUse = true;
  1241.         FWSetFWCommandCompletionProcData (pFWXNodeData->writeAsynchCommandObjectID, (UInt32) pFWXNodeData);
  1242.         FWSetCommonAsynchCommandParams (pFWXNodeData->writeAsynchCommandObjectID,
  1243.                                         pFWXNodeData->fwxUnitInfo.controlAddress.addressHi,
  1244.                                         pFWXNodeData->fwxUnitInfo.controlAddress.addressLo,
  1245.                                         pb->ioBuffer,
  1246.                                         length);
  1247.         status = FWWrite(pFWXNodeData->writeAsynchCommandObjectID);
  1248.         if (status != noErr)
  1249.             pFWXNodeData->writeAsynchCommandObjectInUse = false;
  1250.     }
  1251.     else
  1252.     {
  1253.         pFWXNodeData->fcStopSend = true;
  1254.  
  1255.         // JKL *** can another flow control write be pending? What if there is no
  1256.         //    response?
  1257.         if (!pFWXNodeData->fcSendCommandObjectInUse)
  1258.         {
  1259.             pFWXNodeData->fcSendBuffer[0] = kFCControlRequest;
  1260.             pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->fcIndex;
  1261.             pFWXNodeData->fcSendCommandObjectInUse = true;
  1262.             FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1263.             FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1264.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1265.                                             pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1266.                                             (Ptr) pFWXNodeData->fcSendBuffer,
  1267.                                             kFlowControlSize);
  1268.             status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1269.             if (status != noErr)
  1270.                 pFWXNodeData->fcSendCommandObjectInUse = false;
  1271.         }
  1272.     }
  1273.     return status;
  1274. }
  1275.  
  1276. ////////////////////////////////////////////////////////////////////////////////
  1277. //
  1278. //    SendPacket
  1279. //
  1280. //    Check for the packet needs data to be sent. Pass it off to the senddata
  1281. //    or sendcontrol routine. If no data, complete the command.
  1282. //
  1283.  
  1284. static OSStatus SendPacket(
  1285.     FWXNodeDataPtr            pFWXNodeData)
  1286. {
  1287.     IOParamPtr                pb;
  1288.     OSStatus                status = noErr;
  1289.  
  1290.     if     (pFWXNodeData->fcStopSend)
  1291.         FWDebugStr("\pIn SendPacket with stop flow control");
  1292.  
  1293.     pb = pFWXNodeData->pCurIOParam;
  1294.     if (pb != nil) 
  1295.     {
  1296.         if (pb->ioMisc == (Ptr) kForkData)
  1297.             status = SendDataPacket(pFWXNodeData, pb, pb->ioReqCount);
  1298.         else
  1299.             status = SendControlPacket(pFWXNodeData, pb, pb->ioReqCount);
  1300.     }
  1301.  
  1302.     return status;
  1303. }
  1304.  
  1305. ////////////////////////////////////////////////////////////////////////////////
  1306. //
  1307. //    FWXDriverInterface
  1308. //
  1309. //    Main FireWire File Exchange driver interface.
  1310. //
  1311.  
  1312. OSStatus FWXDriverInterface (
  1313.     FWXInterfaceParamsPtr        pFWXInterfaceParams)
  1314. {
  1315.     FWXNodeDataPtr                pFWXNodeData;
  1316.     IOParamPtr                    pIOPB;
  1317.     UInt32                        interfaceSelector;
  1318.     OSStatus                    err = noErr;
  1319.  
  1320.     // Get our driver and node info
  1321.     pFWXNodeData =
  1322.         (FWXNodeDataPtr) pFWXInterfaceParams->pNodeSpecificData;
  1323.     interfaceSelector = pFWXInterfaceParams->interfaceSelector;
  1324.  
  1325.     // Main dispatch.
  1326.     switch (interfaceSelector) {
  1327.  
  1328.         case kFWXInitialize :
  1329.             err = FWXInitialize((FWXInitializeParamsPtr) pFWXInterfaceParams);
  1330.             break;
  1331.  
  1332.         case kFWXTerminate :
  1333.             err = FWXTerminate((FWXTerminateParamsPtr) pFWXInterfaceParams);
  1334.             break;
  1335.  
  1336.         case kFWXWrite :
  1337.             err = FWXWrite((FWXAsynchParamsPtr) pFWXInterfaceParams);
  1338.             break;
  1339.  
  1340.         case kFWXRead :
  1341.             err = FWXRead((FWXAsynchParamsPtr) pFWXInterfaceParams);
  1342.             break;
  1343.  
  1344.         case kFWXKillIO :
  1345.             pFWXNodeData->writePending = false;
  1346.             
  1347.             // clean up any pending reads
  1348.             err = PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pIOPB);
  1349.             while ((pIOPB != nil) && (err == noErr)) {
  1350.                 pIOPB->ioActCount = 0;
  1351.                 FWXCommandIsComplete(pIOPB, noErr);
  1352.                 err = PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pIOPB);
  1353.             }
  1354.             
  1355.             err = PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pIOPB);
  1356.             while ((pIOPB != nil) && (err == noErr)) {
  1357.                 pIOPB->ioActCount = 0;
  1358.                 FWXCommandIsComplete(pIOPB, noErr);
  1359.                 err = PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pIOPB);
  1360.             }
  1361.             pFWXNodeData->dataPbCount = 0;
  1362.             pFWXNodeData->controlPbCount = 0;
  1363.             pFWXNodeData->dataPbAvail = 0;
  1364.             pFWXNodeData->controlPbAvail = 0;
  1365.             break;
  1366.  
  1367.         case kFWXOpenNode:
  1368.             err = FWXOpenNode((FWXOpenNodeParamsPtr) pFWXInterfaceParams);
  1369.             break;
  1370.  
  1371.         case kFWXCloseNode:
  1372.             err = FWXCloseNode((FWXNodeDataPtr) (pFWXInterfaceParams->pNodeSpecificData));
  1373.             break;
  1374.  
  1375.         default :
  1376.             err = paramErr;
  1377.             break;
  1378.     }
  1379.  
  1380.     return err;
  1381. }
  1382.  
  1383. ////////////////////////////////////////////////////////////////////////////////
  1384. //
  1385. //    FWXInitialize
  1386. //
  1387. //    This routine initializes the FireWire File Exchange driver.  It
  1388. //    allocates a private data record and registers with the FireWire family.
  1389. //
  1390.  
  1391. static OSStatus FWXInitialize(
  1392.     FWXInitializeParamsPtr        pFWXInitializeParams)
  1393. {
  1394.     FWPDriverProtocol            fwPDriverProtocolTable[1];
  1395.     Ptr                            pBuffer = nil;
  1396.     FWXDriverDataPtr            pFWXDriverData;
  1397.     OSStatus                    status = noErr;
  1398.     
  1399. //    FWDebugStr("\pfwix driver init");
  1400.     // Allocate driver data.
  1401.     pFWXDriverData = (FWXDriverDataPtr) PoolAllocateResident(sizeof(FWXDriverData), true);
  1402.     if (pFWXDriverData != nil)
  1403.         pFWXDriverData->fwxDriverID = pFWXInitializeParams->fwxDriverID;
  1404.     else
  1405.         status = memFullErr;
  1406.  
  1407.     // Allocate a control buffer
  1408.     if (status == noErr)
  1409.     {
  1410.         pBuffer = PoolAllocateResident(kFWControlBufferSize, false);
  1411.         if (pBuffer == nil)
  1412.         {
  1413.             PoolDeallocate((Ptr) pFWXDriverData);
  1414.             pFWXDriverData = nil;
  1415.             status = memFullErr;
  1416.         }
  1417.         else
  1418.             pFWXDriverData->controlBuffer = pBuffer;
  1419.     }
  1420.  
  1421.     // Allocate a flow control receive buffer
  1422.     if (status == noErr)
  1423.     {
  1424.         pBuffer = PoolAllocateResident(kFlowControlSize, true);
  1425.         if (pBuffer == nil)
  1426.         {
  1427.             PoolDeallocate(pFWXDriverData->controlBuffer);
  1428.             PoolDeallocate((Ptr) pFWXDriverData);
  1429.             pFWXDriverData = nil;
  1430.             status = memFullErr;
  1431.         }
  1432.         else
  1433.             pFWXDriverData->fcBuffer = pBuffer;
  1434.     }
  1435.  
  1436.     // Register with the FireWire family.
  1437.     if (status == noErr)
  1438.     {
  1439.         status = FWRegisterProtocolDriver (pFWXInitializeParams->pDriverRegEntry,
  1440.                                            &(pFWXDriverData->fwPDriverID),
  1441.                                            (UInt32) pFWXDriverData);
  1442.     }
  1443.  
  1444.     // Set protocol table.
  1445.     if (status == noErr)
  1446.     {
  1447.         fwPDriverProtocolTable[0].specID = 'app';
  1448.         fwPDriverProtocolTable[0].swVersion = 'fwx';
  1449.         status = FWSetPDriverProtocolTable (pFWXDriverData->fwPDriverID,
  1450.                                             &fwPDriverProtocolTable[0],
  1451.                                             1);
  1452.     }
  1453.  
  1454.     // Set unit notification procs.
  1455.     if (status == noErr)
  1456.     {
  1457.         status = FWSetFWPDriverUnitAddedProc (pFWXDriverData->fwPDriverID,
  1458.                                               FWPDriverUnitAdded);
  1459.     }
  1460.     if (status == noErr)
  1461.     {
  1462.         status = FWSetFWPDriverUnitRemovedProc (pFWXDriverData->fwPDriverID,
  1463.                                                 FWPDriverUnitRemoved);
  1464.     }
  1465.  
  1466.     // Scan for units.
  1467.     if (status == noErr)
  1468.         status = FWScanUnitsForFWPDriver (pFWXDriverData->fwPDriverID);
  1469.  
  1470.     // set driver write notify routine
  1471.     if (status == noErr)
  1472.     {
  1473.         status = FWSetFWClientWriteCompleteProc((FWReferenceID) pFWXDriverData->fwPDriverID,
  1474.                                                 FWClientWriteCompleteInterface);
  1475.     }
  1476.  
  1477.     // Get address space for control buffer: allow write and notify on write
  1478.     if (status == noErr)
  1479.     {
  1480.         status = FWAllocateAddressSpace
  1481.                     (&pFWXDriverData->controlAddressSpaceID,
  1482.                      (FWReferenceID) pFWXDriverData->fwPDriverID,
  1483.                      &(pFWXDriverData->controlAddress),
  1484.                      kFWControlBufferSize,
  1485.                      pFWXDriverData->controlBuffer,
  1486.                      kFWAddressWriteEnable | kFWAddressWriteCompleteNotify,
  1487.                      (Ptr) pFWXDriverData);
  1488.     }
  1489.  
  1490.     // Get address space for flow control buffer: allow write, notify on write
  1491.     if (status == noErr)
  1492.     {
  1493.         status = FWAllocateAddressSpace
  1494.                     (&pFWXDriverData->fcAddressSpaceID,
  1495.                      (FWReferenceID) pFWXDriverData->fwPDriverID,
  1496.                      &(pFWXDriverData->fcAddress),
  1497.                      kFlowControlSize,
  1498.                      (Ptr) pFWXDriverData->fcBuffer,
  1499.                      kFWAddressWriteEnable | kFWAddressWriteCompleteNotify,
  1500.                      (Ptr) pFWXDriverData);
  1501.     }
  1502.  
  1503.     // Create a unit directory.
  1504.     if (status == noErr)
  1505.     {
  1506.         status = FWXCreatePDriverUnitDirectory (pFWXDriverData,
  1507.                                                 &(pFWXDriverData->unitCSRROMEntryID));
  1508.     }
  1509.  
  1510.  
  1511.     // Save our driver data or clean up on error.
  1512.     if (status == noErr)
  1513.     {
  1514.         pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData =
  1515.             (Ptr) pFWXDriverData;
  1516.     }
  1517.     else
  1518.     {
  1519.         //zzz should use terminate
  1520.         // deallocate more stuff, asynch object?
  1521.         if (pFWXDriverData->fcBuffer != nil)
  1522.             PoolDeallocate((Ptr) pFWXDriverData->fcBuffer);
  1523.         if (pFWXDriverData->controlBuffer != nil)
  1524.             PoolDeallocate(pFWXDriverData->controlBuffer);
  1525.         if (pFWXDriverData != nil)
  1526.             PoolDeallocate((Ptr) pFWXDriverData);
  1527.  
  1528.         pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData = nil;
  1529.     }
  1530.     return status;
  1531. }
  1532.  
  1533.  
  1534. ////////////////////////////////////////////////////////////////////////////////
  1535. //
  1536. // FWXCreatePDriverUnitDirectory
  1537. //
  1538. //   This routine adds a Configuration ROM unit directory for the protocol driver.
  1539. //zzz must do cleanup on error.
  1540. //
  1541.  
  1542. static OSStatus    FWXCreatePDriverUnitDirectory(
  1543.     FWXDriverDataPtr            pFWXDriverData,
  1544.     CSRROMEntryID                *pFWPDriverCSRROMUnitDirID)
  1545. {
  1546.     CSRROMEntryID                csrROMRootEntryID = kInvalidCSRROMEntryID,
  1547.                                 csrROMUnitDirEntryID = kInvalidCSRROMEntryID,
  1548.                                 csrROMEntryID = kInvalidCSRROMEntryID;
  1549.     FWXUnitInfo                    fwxUnitInfo;
  1550.     UInt32                        immediateEntry;
  1551.     OSStatus                    status = noErr;
  1552.  
  1553.     // Get configuration ROM root directory.
  1554.     status = FWCSRROMGetRootDirectory (pFWXDriverData->fwPDriverID, &csrROMRootEntryID);
  1555.  
  1556.     // Create a new unit directory.
  1557.     if (status == noErr)
  1558.     {
  1559.         status = FWCSRROMCreateEntry (csrROMRootEntryID,
  1560.                                       &csrROMUnitDirEntryID,
  1561.                                       kDirectoryCSRROMEntryType,
  1562.                                       kCSRUnitDirectoryKey,
  1563.                                       nil,
  1564.                                       0);
  1565.         if (status == noErr)
  1566.             pFWXDriverData->unitCSRROMEntryID = csrROMUnitDirEntryID;
  1567.     }
  1568.  
  1569.     // Set unit's spec ID.
  1570.     if (status == noErr)
  1571.     {
  1572.         immediateEntry = 'app ';
  1573.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  1574.                                       &csrROMEntryID,
  1575.                                       kImmediateCSRROMEntryType,
  1576.                                       kCSRUnitSpecIdKey,
  1577.                                       (Ptr) &immediateEntry,
  1578.                                       3);
  1579.     }
  1580.  
  1581.     // Set unit's SW Version.
  1582.     if (status == noErr)
  1583.     {
  1584.         immediateEntry = 'fwx ';
  1585.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  1586.                                       &csrROMEntryID,
  1587.                                       kImmediateCSRROMEntryType,
  1588.                                       kCSRUnitSwVersionKey,
  1589.                                       (Ptr) &immediateEntry,
  1590.                                       3);
  1591.     }
  1592.  
  1593.     // Create unit dependent leaf.
  1594.     if (status == noErr)
  1595.     {
  1596.         // Fill in data for FWiX unit info leaf.
  1597.         fwxUnitInfo.controlAddress.addressHi = pFWXDriverData->controlAddress.addressHi;
  1598.         fwxUnitInfo.controlAddress.addressLo = pFWXDriverData->controlAddress.addressLo;
  1599.         fwxUnitInfo.fcAddress.addressHi = pFWXDriverData->fcAddress.addressHi;
  1600.         fwxUnitInfo.fcAddress.addressLo = pFWXDriverData->fcAddress.addressLo;
  1601.  
  1602.         // Create the leaf.
  1603.         status = FWCSRROMCreateEntry (csrROMUnitDirEntryID,
  1604.                                       &csrROMEntryID,
  1605.                                       kLeafCSRROMEntryType,
  1606.                                       kCSRUnitDependentInfoKey,
  1607.                                       (Ptr) &fwxUnitInfo,
  1608.                                       sizeof (FWXUnitInfo));
  1609.     }
  1610.  
  1611.     // Instantiate CSR ROM.
  1612.     if (status == noErr)
  1613.         status = FWCSRROMInstantiate (pFWXDriverData->fwPDriverID);
  1614.  
  1615.     // Clean up.
  1616.     if (csrROMRootEntryID != (CSRROMEntryID) kInvalidCSRROMEntryID)
  1617.         FWCSRROMDisposeEntryID (csrROMRootEntryID);
  1618.  
  1619.     if (csrROMEntryID != (CSRROMEntryID) kInvalidCSRROMEntryID)
  1620.         FWCSRROMDisposeEntryID (csrROMEntryID);
  1621.  
  1622.     // Return unit directory ID.
  1623.     if (status == noErr)
  1624.         *pFWPDriverCSRROMUnitDirID = csrROMUnitDirEntryID;
  1625.     else
  1626.         *pFWPDriverCSRROMUnitDirID = kInvalidCSRROMEntryID;
  1627.  
  1628.     return (status);
  1629. }
  1630.  
  1631.  
  1632. ////////////////////////////////////////////////////////////////////////////////
  1633. //
  1634. //    FWXTerminate
  1635. //
  1636. //    This routine terminates the FireWire File Exchange driver.  It
  1637. //    deallocates a private data record and unregisters with the FireWire family.
  1638. //zzz need to do more deallocation:
  1639. //        xmit and receive buffers
  1640. //        CSR ROM unit dir entry
  1641. //        
  1642. //
  1643.  
  1644. static OSStatus    FWXTerminate(
  1645.     FWXTerminateParamsPtr        pFWXTerminateParams)
  1646. {
  1647.     FWXDriverDataPtr            pFWXDriverData;
  1648.     OSStatus                    status = noErr;
  1649.  
  1650. //    FWDebugStr("\pfwix driver terminate");
  1651.     // Get driver data from params.
  1652.     pFWXDriverData = (FWXDriverDataPtr)
  1653.         pFWXTerminateParams->fwxInterfaceParams.pDriverSpecificData;
  1654.  
  1655.     // Deallocate our driver data.
  1656.     if (pFWXDriverData != nil) {
  1657.  
  1658.         if (pFWXDriverData->unitCSRROMEntryID != (CSRROMEntryID) kInvalidCSRROMEntryID)
  1659.             FWCSRROMDisposeEntryID (pFWXDriverData->unitCSRROMEntryID);
  1660.  
  1661.         if (pFWXDriverData->controlBuffer != nil)
  1662.             PoolDeallocate((Ptr) pFWXDriverData->controlBuffer);
  1663.         
  1664.         if (pFWXDriverData->fcBuffer != nil)
  1665.             PoolDeallocate((Ptr) pFWXDriverData->fcBuffer);
  1666.         
  1667.         // Unregister with FireWire family.
  1668.         FWUnregisterProtocolDriver(pFWXDriverData->fwPDriverID);
  1669.  
  1670.         // Deallocate our driver data.
  1671.         PoolDeallocate((Ptr) pFWXDriverData);
  1672.     }
  1673.     
  1674.     return status;
  1675. }
  1676.  
  1677. ////////////////////////////////////////////////////////////////////////////////
  1678. //
  1679. //    FWXOpenNode
  1680. //
  1681. //    This routine opens a connections to a remote FWiX node. Allocate a bunch
  1682. //    of buffers and get the remote node's info. Have to send the node our data
  1683. //    address space for him. Use the flow control asynch object and buffers to
  1684. //    handle this. Why? Its there and the right size.
  1685. //
  1686.  
  1687. static OSStatus FWXOpenNode(
  1688.     FWXOpenNodeParamsPtr        pFWXInitializeParams)
  1689. {
  1690.     AddressSpaceID                addressID;
  1691.     FWXDriverDataPtr            pFWXDriverData;
  1692.     FWXNodeDataPtr                pFWXNodeData = nil;
  1693.     CSRROMEntryIterator            csrROMIterator = kInvalidCSRROMIterator;
  1694.     CSRROMSearchCriteria        searchCriteria;
  1695.     CSRROMEntryID                unitCSRROMEntryID,
  1696.                                 unitInfoCSRROMEntryID = kInvalidCSRROMEntryID;
  1697.     UInt32                        unitInfoSize;
  1698.     FWCommandObjectID            asynchCommandObjectID;
  1699.     Boolean                        done;
  1700.     OSStatus                    status = noErr;
  1701.  
  1702. //    FWDebugStr("\pFWXOpenNode");
  1703.     // Get our driver data.
  1704.     pFWXDriverData = (FWXDriverDataPtr) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData;
  1705.  
  1706.     // Allocate a node data record
  1707.     pFWXNodeData = (FWXNodeDataPtr) PoolAllocateResident (sizeof (FWXNodeData), true);
  1708.     if (pFWXNodeData != nil)
  1709.     {
  1710.         pFWXNodeData->fwUnitID =
  1711.             (FWUnitID) pFWXInitializeParams->fwxNodeRegistrationReference;
  1712.         pFWXNodeData->pFWXDriverData = pFWXDriverData;
  1713.     }
  1714.     else
  1715.         status = memFullErr;
  1716.     
  1717.     // Allocate a flow control send buffer
  1718.     if (status == noErr)
  1719.     {        
  1720.         pFWXNodeData->fcSendBuffer = (SInt32 *) PoolAllocateResident(kFlowControlSize, false);
  1721.         if (pFWXNodeData->fcSendBuffer == nil)
  1722.             status = memFullErr;
  1723.     }
  1724.  
  1725.     // Allocate a flow control reply buffer
  1726.     if (status == noErr)
  1727.     {        
  1728.         pFWXNodeData->fcReplyBuffer = (SInt32 *) PoolAllocateResident(kFlowControlSize, false);
  1729.         if (pFWXNodeData->fcReplyBuffer == nil)
  1730.         status = memFullErr;
  1731.     }
  1732.     
  1733.     // Allocate a data done buffer
  1734.     if (status == noErr)
  1735.     {        
  1736.         pFWXNodeData->dataDoneBuffer = (SInt32 *) PoolAllocateResident(kDataDoneBufSize, false);
  1737.         if (pFWXNodeData->dataDoneBuffer == nil)
  1738.         status = memFullErr;
  1739.     }
  1740.  
  1741.     // Allocate a data buffer and get address space, have to send this to the
  1742.     // node after the rest of the allocations
  1743.     if (status == noErr)
  1744.     {        
  1745.         pFWXNodeData->dataBuffer = PoolAllocateResident(kFWDataBufferSize, false);
  1746.         if (pFWXNodeData->dataBuffer != nil)
  1747.         {
  1748.             // Get address space for data buffer: allow write, notify is handled with data done message
  1749.             status = FWAllocateAddressSpace (&addressID,
  1750.                                               (FWReferenceID) pFWXDriverData->fwPDriverID,
  1751.                                               &pFWXNodeData->localDataAddress,
  1752.                                               kFWDataBufferSize,
  1753.                                               pFWXNodeData->dataBuffer,
  1754.                                              kFWAddressWriteEnable,
  1755.                                              (Ptr) pFWXDriverData);
  1756.         }
  1757.         else
  1758.             status = memFullErr;
  1759.     }
  1760.  
  1761.     // Add node data record to driver's list.
  1762.     if (status == noErr)
  1763.     {
  1764.         if (pFWXDriverData->fwxNodeDataList != nil)
  1765.             pFWXDriverData->fwxNodeDataList->pPrevFWXNodeData = pFWXNodeData;
  1766.  
  1767.         pFWXNodeData->pPrevFWXNodeData = nil;
  1768.         pFWXNodeData->pNextFWXNodeData = pFWXDriverData->fwxNodeDataList;
  1769.  
  1770.         pFWXDriverData->fwxNodeDataList = pFWXNodeData;
  1771.     }
  1772.  
  1773.     // Get node's device ID.
  1774.     if (status == noErr)
  1775.     {
  1776.         status = FWGetFWDeviceIDFromFWReferenceID ((FWReferenceID) pFWXNodeData->fwUnitID,
  1777.                                                    &(pFWXNodeData->fwDeviceID));
  1778.     }
  1779.  
  1780.     // Get node's unit dependent information.
  1781.     if (status == noErr)
  1782.     {
  1783.         // Get unit CSR ROM entry ID.
  1784.         status = FWGetUnitCSRROMEntryID ((FWReferenceID) pFWXNodeData->fwUnitID,
  1785.                                          &unitCSRROMEntryID);
  1786.  
  1787.         // Create a CSR ROM search iterator.
  1788.         if (status == noErr) {
  1789.             status = FWCSRROMCreateIterator (&csrROMIterator,
  1790.                                              (FWReferenceID) pFWXNodeData->fwUnitID);
  1791.         }
  1792.  
  1793.         // Set iterator to start searching at our unit directory.
  1794.         if (status == noErr) {
  1795.             status = FWCSRROMSetIterator (csrROMIterator,
  1796.                                           unitCSRROMEntryID,
  1797.                                           kIterateDescendants);
  1798.         }
  1799.  
  1800.         // Search for unit dependent info leaf.
  1801.         if (status == noErr) {
  1802.             searchCriteria.csrROMSearchType = kCSRROMSearchForKey;
  1803.             searchCriteria.keyType = kCSRLeafKeyTypeBit;
  1804.             searchCriteria.keyHi = kCSRUnitDependentInfoKeyHiBit;
  1805.             searchCriteria.keyLo = kCSRUnitDependentInfoKeyLoBit;
  1806.             unitInfoSize = sizeof (FWXUnitInfo);
  1807.             status = FWCSRROMEntrySearch (csrROMIterator,
  1808.                                           kIterateContinue,
  1809.                                           &unitInfoCSRROMEntryID,
  1810.                                           &done,
  1811.                                           &searchCriteria,
  1812.                                           (Ptr) &(pFWXNodeData->fwxUnitInfo),
  1813.                                           &unitInfoSize);
  1814.         }
  1815.  
  1816.         // Clean up.
  1817.         if (csrROMIterator != (CSRROMEntryIterator) kInvalidCSRROMIterator)
  1818.             FWCSRROMDisposeIterator (csrROMIterator);
  1819.         if (unitInfoCSRROMEntryID != (CSRROMEntryIterator) kInvalidCSRROMEntryID)
  1820.             FWCSRROMDisposeEntryID (unitInfoCSRROMEntryID);
  1821.     }
  1822.  
  1823.     // Allocate FireWire command object for sending asynchronous write packets.
  1824.     if (status == noErr)
  1825.     {
  1826.         status = FWAllocateAsynchCommandObject(&asynchCommandObjectID);
  1827.         if (status == noErr)
  1828.         {
  1829.             pFWXNodeData->writeAsynchCommandObjectID = asynchCommandObjectID;
  1830.             FWSetFWCommandParams(asynchCommandObjectID,
  1831.                                  (FWReferenceID) pFWXNodeData->fwUnitID,
  1832.                                  0,
  1833.                                  FWXWriteCompletion,
  1834.                                  (UInt32) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData);
  1835.             FWSetAsynchCommandMaxRetries(asynchCommandObjectID, 8);
  1836.         }
  1837.     }
  1838.  
  1839. #ifdef FireBug
  1840.     FireBugPrep ((FWReferenceID) pFWXNodeData->fwUnitID);
  1841.     sprintf (fireBug, "FWiX FireBug service ready on %s", "(unknown)");    // could add some kind of ID
  1842.     FireBugMsg (fireBug);
  1843. #endif
  1844.  
  1845.     // Allocate FireWire command object for sending flow control packets.
  1846.     if (status == noErr)
  1847.     {
  1848.         status = FWAllocateAsynchCommandObject(&asynchCommandObjectID);
  1849.         if (status == noErr)
  1850.         {
  1851.             pFWXNodeData->fcSendCommandObjectID = asynchCommandObjectID;
  1852.             FWSetFWCommandParams (asynchCommandObjectID,
  1853.                              (FWReferenceID) pFWXNodeData->fwUnitID,
  1854.                              0,
  1855.                 FlowControlComplete,
  1856.                 (UInt32) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData);
  1857.         FWSetAsynchCommandMaxRetries(asynchCommandObjectID, 8);
  1858.     }
  1859.     }
  1860.  
  1861.     // Allocate FireWire command object for replying with flow control packets.
  1862.     if (status == noErr)
  1863.     {
  1864.         status = FWAllocateAsynchCommandObject(&asynchCommandObjectID);
  1865.         if (status == noErr)
  1866.         {
  1867.             pFWXNodeData->fcReplyCommandObjectID = asynchCommandObjectID;
  1868.             FWSetFWCommandParams(asynchCommandObjectID,
  1869.                 (FWReferenceID) pFWXNodeData->fwUnitID,
  1870.                 0,
  1871.                 FlowControlReplyComplete,
  1872.                 (UInt32) pFWXInitializeParams->fwxInterfaceParams.pDriverSpecificData);
  1873.             FWSetAsynchCommandMaxRetries(asynchCommandObjectID, 8);
  1874.         }
  1875.     }
  1876.  
  1877.     // setup IO queues
  1878.     if (status == noErr)
  1879.         status = SetupIOQueues(pFWXNodeData);
  1880.  
  1881.     if (status == noErr)
  1882.         FWSetMaxPayloadSize((FWReferenceID) pFWXNodeData->fwUnitID, kFWPacketSize);
  1883.  
  1884.     // Open a connection to the unit.
  1885.     if (status == noErr) {
  1886.         status = FWAddUnitConnection
  1887.                     (pFWXNodeData->fwUnitID, (FWReferenceID) pFWXDriverData->fwPDriverID);
  1888.         if (status == noErr)
  1889.             pFWXNodeData->unitConnectionAdded = true;
  1890.     }
  1891.  
  1892.     // Init control packets to some safe value, this will enable flow control to start
  1893.     if (status == noErr)
  1894.     {
  1895.         pFWXNodeData->controlPbAvail = 5;
  1896.     }
  1897.  
  1898.     // Send the data address space to the remote node using the flow control request packet
  1899.     // JKL *** can this fail, retry?
  1900.     if (status == noErr)
  1901.     {
  1902.         pFWXNodeData->fcSendCommandObjectInUse = true;
  1903.         pFWXNodeData->fcSendBuffer[0] = kAddressInfoRequest;
  1904.         pFWXNodeData->fcSendBuffer[1] = pFWXNodeData->localDataAddress.addressHi;
  1905.         pFWXNodeData->fcSendBuffer[2] = pFWXNodeData->localDataAddress.addressLo;
  1906.         FWSetFWCommandCompletionProcData (pFWXNodeData->fcSendCommandObjectID, (UInt32) pFWXNodeData);
  1907.         FWSetCommonAsynchCommandParams (pFWXNodeData->fcSendCommandObjectID,
  1908.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressHi,
  1909.                                         pFWXNodeData->fwxUnitInfo.fcAddress.addressLo,
  1910.                                         (Ptr) pFWXNodeData->fcSendBuffer,
  1911.                                         kFlowControlSize);
  1912.         status = FWWrite(pFWXNodeData->fcSendCommandObjectID);
  1913.         if (status != noErr)
  1914.             pFWXNodeData->fcSendCommandObjectInUse = false;
  1915.     }
  1916.     
  1917.     // Clean up on error.
  1918.     if (status != noErr) {
  1919.         if (pFWXNodeData != nil)
  1920.         {
  1921.             sprintf(debugStr,"Closing node from OpenNode, error: %ld", status);
  1922.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  1923.             FWXCloseNode (pFWXNodeData);
  1924.         }
  1925.     }
  1926.  
  1927.     // Return results.
  1928.     if (status == noErr)
  1929.         pFWXInitializeParams->fwxInterfaceParams.pNodeSpecificData = (Ptr) pFWXNodeData;
  1930.     else
  1931.         pFWXInitializeParams->fwxInterfaceParams.pNodeSpecificData = nil;
  1932.  
  1933.     return status;
  1934. }
  1935.  
  1936. ////////////////////////////////////////////////////////////////////////////////
  1937. //
  1938. //    FWXCloseNode
  1939. //
  1940. //    This routine closes a connections to a remote FWiX node.
  1941. //
  1942. static OSStatus FWXCloseNode(
  1943.     FWXNodeDataPtr                pFWXNodeData)
  1944. {
  1945.     FWXDriverDataPtr            pFWXDriverData;
  1946.     FWXNodeDataPtr                pPrevFWXNodeData,
  1947.                                 pNextFWXNodeData;
  1948.     volatile Boolean            *pFWCommandObjectInUse;
  1949.     IOParamPtr                    pIOPB;
  1950.     AbsoluteTime                timeRemaining;
  1951.     OSStatus                    status = noErr;
  1952.  
  1953. //    FWDebugStr("\pFWXCloseNode");
  1954.     if (pFWXNodeData != nil) {
  1955.         // Get our driver data.
  1956.         pFWXDriverData = (FWXDriverDataPtr) pFWXNodeData->pFWXDriverData;
  1957.  
  1958.         // Set node closed.
  1959.         pFWXNodeData->closed = true;
  1960.         CancelTimer(pFWXNodeData->fcTimerID, &timeRemaining);
  1961.  
  1962.         // Wait for all command objects to be no longer in use.
  1963.         pFWCommandObjectInUse = &(pFWXNodeData->writeAsynchCommandObjectInUse);
  1964.         while (*pFWCommandObjectInUse);
  1965.         pFWCommandObjectInUse = &(pFWXNodeData->fcSendCommandObjectInUse);
  1966.         while (*pFWCommandObjectInUse);
  1967.         pFWCommandObjectInUse = &(pFWXNodeData->fcReplyCommandObjectInUse);
  1968.         while (*pFWCommandObjectInUse);
  1969.  
  1970.         // Deallocate queues, write queue
  1971.         if (pFWXNodeData->pWriteQHdr != nil) {
  1972.             pIOPB = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  1973.             while (pIOPB != nil) {
  1974.                 PBDequeueFirst(pFWXNodeData->pWriteQHdr, (QElemPtr *) &pIOPB);
  1975.                 pIOPB->ioActCount = 0;
  1976.                 FWXCommandIsComplete(pIOPB, noErr);
  1977.                 pIOPB = (IOParamPtr) pFWXNodeData->pWriteQHdr->qHead;
  1978.             }
  1979.             PBQueueDelete(pFWXNodeData->pWriteQHdr);
  1980.         }
  1981.         
  1982.         if (pFWXNodeData->pReadControlQHdr != nil) {
  1983.             pIOPB = (IOParamPtr) pFWXNodeData->pReadControlQHdr->qHead;
  1984.             while (pIOPB != nil) {
  1985.                 PBDequeueFirst(pFWXNodeData->pReadControlQHdr, (QElemPtr *) &pIOPB);
  1986.                 pIOPB->ioActCount = 0;
  1987.                 FWXCommandIsComplete(pIOPB, noErr);
  1988.                 pIOPB = (IOParamPtr) pFWXNodeData->pReadControlQHdr->qHead;
  1989.             }
  1990.             PBQueueDelete(pFWXNodeData->pReadControlQHdr);
  1991.         }
  1992.  
  1993.         if (pFWXNodeData->pReadDataQHdr != nil) {
  1994.             pIOPB = (IOParamPtr) pFWXNodeData->pReadDataQHdr->qHead;
  1995.             while (pIOPB != nil) {
  1996.                 PBDequeueFirst(pFWXNodeData->pReadDataQHdr, (QElemPtr *) &pIOPB);
  1997.                 pIOPB->ioActCount = 0;
  1998.                 FWXCommandIsComplete(pIOPB, noErr);
  1999.                 pIOPB = (IOParamPtr) pFWXNodeData->pReadDataQHdr->qHead;
  2000.             }
  2001.             PBQueueDelete(pFWXNodeData->pReadDataQHdr);
  2002.             pFWXNodeData->dataPbCount = 0;
  2003.             pFWXNodeData->controlPbCount = 0;
  2004.             pFWXNodeData->dataPbAvail = 0;
  2005.             pFWXNodeData->controlPbAvail = 0;
  2006.         }
  2007.  
  2008.         // Deallocate command object for sending asynchronous write packets.
  2009.         if (pFWXNodeData->writeAsynchCommandObjectID != (FWCommandObjectID) kInvalidFWCommandObjectID)
  2010.             FWDeallocateFWCommandObject (pFWXNodeData->writeAsynchCommandObjectID);
  2011.  
  2012.         // Deallocate command objects for flow control packets.
  2013.         if (pFWXNodeData->fcSendCommandObjectID != (FWCommandObjectID) kInvalidFWCommandObjectID)
  2014.             FWDeallocateFWCommandObject (pFWXNodeData->fcSendCommandObjectID);
  2015.         if (pFWXNodeData->fcReplyCommandObjectID != (FWCommandObjectID) kInvalidFWCommandObjectID)
  2016.             FWDeallocateFWCommandObject (pFWXNodeData->fcReplyCommandObjectID);
  2017.  
  2018.         // Remove node data record from driver's list.
  2019.         pPrevFWXNodeData = pFWXNodeData->pPrevFWXNodeData;
  2020.         pNextFWXNodeData = pFWXNodeData->pNextFWXNodeData;
  2021.  
  2022.         // Remove our connection to unit.
  2023.         if (pFWXNodeData->unitConnectionAdded) {
  2024.             FWRemoveUnitConnection (pFWXNodeData->fwUnitID,
  2025.                                     (FWReferenceID) pFWXDriverData->fwPDriverID);
  2026.         }
  2027.  
  2028.         if (pPrevFWXNodeData != nil) {
  2029.             pPrevFWXNodeData->pNextFWXNodeData = pNextFWXNodeData;
  2030.         } else {
  2031.             if (pFWXDriverData->fwxNodeDataList == pFWXNodeData)
  2032.                 pFWXDriverData->fwxNodeDataList = pNextFWXNodeData;
  2033.         }
  2034.  
  2035.         if (pNextFWXNodeData != nil)
  2036.             pNextFWXNodeData->pPrevFWXNodeData = pPrevFWXNodeData;
  2037.  
  2038.         // Deallocate buffers
  2039.         if (pFWXNodeData->fcSendBuffer != nil)
  2040.             PoolDeallocate ((Ptr) pFWXNodeData->fcSendBuffer);
  2041.         if (pFWXNodeData->fcReplyBuffer != nil)
  2042.             PoolDeallocate ((Ptr) pFWXNodeData->fcReplyBuffer);
  2043.         if (pFWXNodeData->dataDoneBuffer != nil)
  2044.             PoolDeallocate ((Ptr) pFWXNodeData->dataDoneBuffer);
  2045.         if (pFWXNodeData->dataBuffer != nil)
  2046.             PoolDeallocate((Ptr) pFWXNodeData->dataBuffer);
  2047.  
  2048.         // Deallocate node data record.
  2049.         PoolDeallocate ((Ptr) pFWXNodeData);
  2050.     }
  2051.  
  2052.     return status;
  2053. }
  2054.  
  2055. //////////////////////////////////////////////////////////////////////////////
  2056. //
  2057. //    SetupIOQueues
  2058. //
  2059. //    Setup the queueus. Create and initialize.
  2060. //
  2061. static OSStatus SetupIOQueues(
  2062.     FWXNodeDataPtr        pFWXNodeData)
  2063. {
  2064.     OSStatus            status = noErr;
  2065.     
  2066.     status = PBQueueCreate(& pFWXNodeData->pReadDataQHdr);
  2067.     if (status == noErr)
  2068.         PBQueueInit(pFWXNodeData->pReadDataQHdr);
  2069.     else
  2070.         return status;
  2071.         
  2072.     status = PBQueueCreate(& pFWXNodeData->pReadControlQHdr);
  2073.     if (status == noErr)
  2074.         PBQueueInit(pFWXNodeData->pReadControlQHdr);
  2075.     else
  2076.         return status;
  2077.         
  2078.         status = PBQueueCreate(& pFWXNodeData->pWriteQHdr);
  2079.         if (status == noErr)
  2080.             PBQueueInit(pFWXNodeData->pWriteQHdr);
  2081.     
  2082.     return status;    
  2083. }    
  2084.  
  2085. //////////////////////////////////////////////////////////////////////////////
  2086. //
  2087. //    FWXGetNodeDataFromNodeID
  2088. //
  2089. //    Return the FWX node data record that matches the given node ID.
  2090. //
  2091. static OSStatus FWXGetNodeDataFromNodeID (
  2092.     FWXDriverDataPtr            pFWXDriverData,
  2093.     UInt32                        generation,
  2094.     UInt32                        nodeID,
  2095.     FWXNodeDataPtr                *ppFWXNodeData)
  2096. {
  2097.     FWXNodeDataPtr                pFWXNodeData;
  2098.     FWDeviceID                    fwDeviceID;
  2099.     Boolean                        found;
  2100.     OSStatus                    status = noErr;
  2101.  
  2102.     // Get FireWire device ID for nodeID.
  2103.     status = FWFindFWDeviceFromNodeID (pFWXDriverData->fwPDriverID,
  2104.                                        generation,
  2105.                                        nodeID,
  2106.                                        &fwDeviceID);
  2107.  
  2108.     // Search node data list for node with matching deviceID.
  2109.     if (status == noErr) {
  2110.         pFWXNodeData = pFWXDriverData->fwxNodeDataList;
  2111.         found = false;
  2112.         while ((pFWXNodeData != nil) && (!found))
  2113.         {
  2114.             if ((pFWXNodeData->fwDeviceID == fwDeviceID) && (!(pFWXNodeData->closed)))
  2115.                 found = true;
  2116.             else
  2117.                 pFWXNodeData = pFWXNodeData->pNextFWXNodeData;
  2118.         }
  2119.     }
  2120.  
  2121.     // Return results.
  2122.     if (status == noErr) {
  2123.         if (found) {
  2124.             *ppFWXNodeData = pFWXNodeData;
  2125.         } else {
  2126.             *ppFWXNodeData = nil;
  2127.             status = notFoundErr;
  2128.         }
  2129.     } else {
  2130.         *ppFWXNodeData = nil;
  2131.     }
  2132.  
  2133.     return (status);
  2134. }
  2135.